// 扩展小程序promise的finally方法
Promise.prototype.finally = function(callback) {
  var Promise = this.constructor
  return this.then(
    function(value) {
      Promise.resolve(callback()).then(function() {
        return value
      })
    },
    function(reason) {
      Promise.resolve(callback()).then(function() {
        throw reason
      })
    }
  )
}

// 拦截器、过滤器 类
class Interceptor {
  constructor(params) {
    this.handlers = {}
  }
  on(eventType, handler) {
    var self = this
    if (eventType in self.handlers) {
      console.warn('已注册，重新注册覆盖')
    }
    self.handlers[eventType] = handler
    return this
  }
  // 触发事件(发布事件)
  emit(eventType) {
    var self = this
    let handlerArgs = Array.prototype.slice.call(arguments, 1)
    // console.warn(`触发事件${eventType}`);
    return self.handlers[eventType](...handlerArgs)
  }
  // 删除订阅事件
  off(eventType, handler) {
    var currentEvent = this.handlers[eventType]
    var len = 0
    if (currentEvent) {
      len = currentEvent.length
      for (var i = len - 1; i >= 0; i--) {
        if (currentEvent[i] === handler) {
          currentEvent.splice(i, 1)
        }
      }
    }
    return this
  }
}
const _transformRequest = new Interceptor()
const _transformResponse = new Interceptor()

class Fetch {
  constructor(params) {
    if (typeof Fetch.instance === 'object') {
      return Fetch.instance //防止被篡改
    }
    Fetch.instance = this
    this.default = {
      method: 'get',
      baseURL: '',
      transformRequest(arr = []) {
        arr.length == 0 &&
          _transformRequest
            .on('transformRequestResolve', response => {
              return response
            })
            .on('transformRequestReject', err => {
              return err
            })
        arr.length >= 1 &&
          _transformRequest.on('transformRequestResolve', arr[0]) &&
          arr.length == 1 &&
          _transformRequest.on('transformRequestReject', err => {
            return err
          })
        arr.length >= 2 &&
          _transformRequest.on('transformRequestReject', arr[1])
      },
      transformResponse(arr = []) {
        arr.length == 0 &&
          _transformResponse
            .on('transformResponseResolve', response => {
              return response
            })
            .on('transformResponseReject', response => {
              return response
            })
        arr.length >= 1 &&
          _transformResponse.on('transformResponseResolve', arr[0]) &&
          arr.length == 1 &&
          _transformResponse.on('transformResponseReject', response => {
            return response
          })
        arr.length >= 2 &&
          _transformResponse.on('transformResponseReject', arr[1])
      },
      async: true,
      headers: {},
      params: {},
      data: {},
      timeout: 60000,
      source: 'SINGLE',
      responseType: 'json',
      withCredentials: false,
      adapter(config) {},
      beforeSend(parms) {
        return parms
      },
      onUploadProgress(progressEvent) {},
      onDownloadProgress(progressEvent) {},
      validateStatus(status) {
        return status >= 200 && status < 300
      },
      ...params
    }
    this.default.transformRequest()
    this.default.transformResponse()
  }
  //  集中处理 非ajax 方法产生的请求
  _methodMedataHandle(url, method, data, config) {
    let obj = {
      url,
      method,
      data,
      ...config
    }
    !obj.data && (obj.data = {})
    return obj
  }
  //ajax 数据预处理
  _dataHandle(params) {
    if (typeof params != 'object') {
      throw new Error('请求参数有误,参数不是一个对象')
    }
    !params.method && (params.method = this.default.method)
    params.method && (params.method = params.method.toUpperCase())
    if (
      !params.url.includes('http://') &&
      !params.url.includes('https://') &&
      this.default.baseURL != ''
    ) {
      params.url = this.default.baseURL + params.url;
      
    }
    //console.log('ajax',params);
    params.headers = {
      ...this.default.headers,
      ...params.headers
    }
    params.params = {
      ...this.default.params,
      ...params.params
    }

    // 把参数改为对象
    // params.data = {
    //   ...this.default.data,
    //   ...params.data,
    // }
    if (params.async != false && params.async != true) {
      params.async = this.default.async
    }
    let str = ''
    Object.keys(params.params).forEach(key => {
      str += `${key}=${params.params[key]}&`
    })
    if (str != '') {
      str = str.substring(0, str.length - 1)
      let [urlKeys, keys] = params.url.split('?')
      if (keys) {
        params.url = `${urlKeys}?${keys}&${str}`
      } else {
        params.url += `?${str}`
      }
    }

    if (params.method != 'get') {
      params.body = JSON.stringify(params.data)
    }
    if( typeof params.data !== 'object' ){
      params.url += `/${params.data}`
    }
    return this
  }
  // 请求前拦截器
  _transformRequestHandle(data) {
    if (typeof data === 'object' || typeof data === 'string') {
      try {
        if (typeof data === 'string') {
          let o = JSON.parse(data || null)
        }
        return _transformRequest.emit('transformRequestResolve', data)
      } catch (err) {
        console.error(err)
        return Promise.reject(err)
      }
    } else {
      return _transformRequest.emit('transformRequestReject', data)
    }
  }
  // 请求后拦截器
  _transformResponseHandle(eventType, response) {
    let data = {}
    try {
      if (eventType === 'transformResponseResolve') {
        data = _transformResponse.emit(eventType, response)
      } else {
        data = _transformResponse.emit(eventType, response)
      }
    } catch (error) {
      console.error(error)
      data = {}
    }
    // 判断是否是Promise对象
    if (Object.prototype.toString.call(data) != '[object Promise]') {
      if (eventType === 'transformResponseResolve') {
        return Promise.resolve(data)
      } else {
        return Promise.reject(data)
      }
    } else {
      return data
    }
  }
  _request(params) {
    return new Promise((resolve, reject) => {
      this._requestAjax(params)
        .then(result => {
          this._transformResponseHandle('transformResponseResolve', {
            ...result,
            ajax: params,
            $default: this.default
          })
            .then(result => {
              resolve(result)
            })
            .catch(error => {
              reject(error)
            })
        })
        .catch(err => {
          this._transformResponseHandle('transformResponseReject', {
            ...err,
            ajax: params,
            $default: this.default
          })
            .then(result => {
              resolve(result)
            })
            .catch(error => {
              reject(error)
            })
        })
        .finally(data => {
          if (data) console.log('finally', data)
          // wx.hideLoading();
          // wx.hideNavigationBarLoading();
        })
    })
  }
  _requestAjax(params) {
    return new Promise((resolve, reject) => {
      wx.request({
        url: params.url,
        data: params.data,
        method: params.method,
        header: params.headers,
        success: result => {
          resolve(result)
        },
        fail: err => {
          reject(err)
        }
      })
    })
  }
  // 统一请求流程
  _ajax(params) {
    // 提前处理
    params = this.default.beforeSend(params)
    // 处理
    this._dataHandle(params)
    params.data = this._transformRequestHandle(params.data)
    // 请求
    return this._request(params)
  }
  _allAjax(arr) {
    let ajaxArr = [],
      alias = false
    arr.forEach(params => {
      if (params.alias) {
        alias = true
      }
      !params.data && (params.data = {})
      // 提前处理
      params = this.default.beforeSend(params)
      // 处理
      this._dataHandle(params)
      params.data = this._transformRequestHandle(params.data)
      ajaxArr.push(this._requestAjax(params))
      // 请求
    })
    return new Promise((resolve, reject) => {
      Promise.all(ajaxArr)
        .then(values => {
          let obj = {},
            t = false
          if (alias) {
            let j = 1
            for (let i = 0; i < values.length; i++) {
              if (arr[i].alias) {
                obj[arr[i].alias] = values[i]
                obj[arr[i].alias].ajax = arr[i]
              } else {
                obj['interface' + j] = values[i]
                j++
                obj['interface' + j].ajax = arr[i]
              }
            }
            obj.source = 'CONCURRENT'
          } else {
            values.forEach((item, index) => {
              item.ajax = arr[index]
            })
            obj = values
          }
          this._transformResponseHandle('transformResponseResolve', obj)
            .then(result => {
              resolve(result)
            })
            .catch(error => {
              reject(error)
            })
        })
        .catch(err => {
          this._transformResponseHandle('transformResponseReject', {
            ...err
          })
            .then(result => {
              resolve(result)
            })
            .catch(error => {
              reject(error)
            })
        })
    })
  }
  ajax(params) {
    let obj = {
      ...params
    }
    return this._ajax(obj)
  }
  get(url, data, config) {
    let obj = this._methodMedataHandle(url, 'get', data, config)
    return this.ajax(obj)
  }
  post(url, data, config) {
    let obj = this._methodMedataHandle(url, 'post', data, config)
    return this.ajax(obj)
  }
  put(url, data, config) {
    let obj = this._methodMedataHandle(url, 'put', data, config)
    return this.ajax(obj)
  }
  delete(url, data, config) {
    let obj = this._methodMedataHandle(url, 'delete', data, config)
    return this.ajax(obj)
  }
  all(arr) {
    // let obj = this._methodMedataHandle(url, 'delete', data, config);
    let obj = JSON.parse(JSON.stringify(arr) || null)
    return this._allAjax(obj)
  }
  api(url,data,method,config){
    let obj = this._methodMedataHandle(url, method, data, config)
    return this.ajax(obj)
  }
}

const fetchAjax = new Fetch()

export default {
  // Ajax: fetchAjax,
  default: fetchAjax.default,
  ajax(params) {
    return fetchAjax.ajax(params)
  },
  get(url, data, config) {
    return fetchAjax.get(url, data, config)
  },
  post(url, data, config) {
    return fetchAjax.post(url, data, config)
  },
  put(url, data, config) {
    return fetchAjax.put(url, data, config)
  },
  delete(url, data, config) {
    return fetchAjax.delete(url, data, config)
  },
  all(arr) {
    return fetchAjax.all(arr)
  },
  cloud(url, data) {
    return
  },
  api(url,data,method,config){
    return fetchAjax.api(url,data,method,config)
  }
}
